# -*- coding: utf-8 -*-
import hashlib
import logging
import time

from flask import request, url_for

from . import api
from . import utils

LOGGER = logging.getLogger(__name__)


# Networks
@api.route('/networks')
def list_networks():
    args = request.args
    project_id = args['project_id']
    # cluster_id = args['cluster_id']
    cluster_ids = utils.get_project_clusters_ids(project_id, support_vpc=True)
    if not cluster_ids:
        return {'status': 1, 'msg': 'fail', 'data': u'没有集群支持VPC'}

    cluster_id = cluster_ids[0]
    s, m = utils.list_networks(project_id, cluster_id)
    return {'status': s, 'msg': 'fail' if s else 'success', 'data': m}


@api.route('/networks', methods=['POST'])
def get_me_a_network():
    """ Create a network and the rest which is neccesarry to boot a network.

    Steps:
      1. net_create: --shared, `net_name`
      2. subnet_create: cidr, network_id, ip_version=4
      3. router_create
      4. router_interface_add
      5. [TODO] router_gateway_set
      6. [TODO] router_route_add

    $ neutron net-create --shared private-shared-network
    $ neutron subnet-create --name private-shared-network 10.0.0.0/24
    $ neutron router-create private-shared-router
    $ neutron router-interface-add private-shared-router private-shared-subnet
    $ neutron router-gateway-set private-shared-router public-network
    """
    args = request.form

    x_user = request.headers['user_name']

    project_id = args['project_id']
    cluster_ids = utils.get_project_clusters_ids(project_id, support_vpc=True)
    LOGGER.debug('cluster of project(%s): %s', project_id, cluster_ids)
    if cluster_ids is None:
        return {'status': 1, 'msg': 'abort', 'data': 'no attached cluster.'}

    # FIXME: 暂时只用第一个集群ID
    cluster_id = cluster_ids[0]

    net_name = args['name']
    net_cidr = args['cidr']
    # shared = args.get('shared') or False
    # external = args.get('external') or False
    subnet_name = args['subnet_name']
    subnet_cidr = args['subnet_cidr']

    # net-create
    s, m = utils.create_network(cluster_id, net_name, net_cidr)
    if s:
        return {'status': s, 'msg': 'fail', 'data': m}

    net = m
    # record net
    utils.record_network(network_id=net['id'], name=net_name,
                         cidr=net_cidr, project_id=project_id,
                         cluster_id=cluster_id, creator=x_user,
                         create_time=utils.curtime())

    LOGGER.debug('network result: %s', net)

    # subnet-create
    s, m = utils.create_subnet(cluster_id, subnet_name,
                               subnet_cidr, net['id'])
    if s:
        return {'status': s, 'msg': 'fail', 'data': m}
    subnet = m
    # record subnet
    utils.record_subnet(network_id=net['id'], subnet_id=subnet['id'],
                        name=subnet_name, cidr=subnet_cidr,
                        status='ACTIVE', creator=x_user,
                        create_time=utils.curtime())

    # router-create
    s, m = utils.create_router(cluster_id, net_name+'_router')
    if s:
        LOGGER.error('Create router failed: %s', m)
        return {'status': s, 'msg': 'fail', 'data': m}

    router = m
    # record router
    utils.record_router(router_id=router['id'], router_name=router['name'],
                        project_id=project_id, cluster_id=cluster_id,
                        creator=x_user, create_time=utils.curtime())

    # router-interface-add
    s, m = utils.add_router_interface(cluster_id, router['id'], subnet['id'])

    # record route
    rtb_id = hashlib.md5(str(time.time())).hexdigest()
    utils.record_route_table(rtb_id=rtb_id,
                             network_id=net['id'],
                             name='rtb_'+router['name']+'_default',
                             router_id=router['id'],
                             is_active=1,
                             creator=x_user, create_time=utils.curtime())

    utils.record_route(rtb_id=rtb_id,
                       subnet_id=subnet['id'],
                       type='Local',
                       is_local=1,
                       creator=x_user,
                       create_time=utils.curtime())

    if s:
        LOGGER.error('Add router interface failed: %s', m)
        return {'status': s, 'msg': 'fail', 'data': m}

    LOGGER.debug('Router interface: %s', m)
    _scheme = request.headers.get('X-Forwarded-Proto', 'http')
    headers = {'Location': url_for('api.show_network',
                                   network_id=net['id'],
                                   _external=True,
                                   _scheme=_scheme)}
    return {
        'status': 0,
        'msg': 'success',
        'data': {
            'network': net,
            'subnet': subnet,
            'router': router,
        }
    }, 201, headers


# Network
@api.route('/networks/<network_id>')
def show_network(network_id):
    s, m = utils.show_network(0, network_id)
    return {'status': s, 'msg': 'fail' if s else 'success', 'data': m}


@api.route('/networks/<network_id>', methods=['DELETE'])
def delete_whole_network(network_id):
    """ Delete whole network and associated resources.

    Steps:
      1. Get subnet list.
      2. Remove these subnets one by one.
      3. Remove the network.
    """

    # args = request.form

    # project_id = args['project_id']
    cluster_ids = utils.get_cluster_ids_by_network(network_id)

    if cluster_ids is None:
        return {'status': 1, 'msg': 'abort', 'data': u'无此网络'}

    delete_net_error = {}
    delete_subnet_error = {}
    for cluster_id in cluster_ids:
        # Find sub-nets
        s, m = utils.get_subnets_by_network(network_id)
        if s:
            return {'status': 1, 'msg': 'fail', 'data': 'Find sub-nets failed!'}
        elif not m:
            # return {'status': 404, 'msg': 'fail', 'data': 'No sub-nets found!'}
            LOGGER.warning('No sub-nets found for network %s!', network_id)

        subnet_list = m

        # Remove sub-nets
        results = []
        for subnet in subnet_list:
            s, m = utils.delete_subnet(subnet['subnet_id'], subnet['cluster_id'])
            if s:
                results.append([subnet['subnet_id'], m])

        if results:
            LOGGER.critical('Delete subnet failed: %r', results)
            # data = u'删除子网失败'
            # return {
            #     'status': len(results),
            #     'msg': msg,
            #     'data': data,
            # }
            delete_subnet_error[cluster_id] = results

        # Delete net
        s, m = utils.delete_network(cluster_id, network_id)
        if not s:
            utils.record_network_remove(network_id)
            # return {'status': 0,
            #         'msg': 'ok',
            #         'data': u'删除%s成功!' % network_id}
        else:
            LOGGER.error('Delete network %s failed: %s', network_id, m)
            delete_net_error[cluster_id] = m
            # return {'status': 1, 'msg': 'fail', 'data': m}

    if delete_net_error:
        return {'status': 0xa,
                'msg': 'fail',
                'data': u'删除网络失败:\n%s' % delete_net_error}
    elif delete_subnet_error:
        return {'status': 0xb,
                'msg': 'fail',
                'data': u'删除子网失败:\n%s' % delete_subnet_error}
    return {
        'status': 0,
        'msg': 'ok',
        'data': u'删除网络成功!'
    }


# Subnets
@api.route('/subnets')
def list_subnets():
    args = request.args
    project_id = args['project_id']
    s, m = utils.list_subnets_in_project(project_id)
    return {'status': s, 'msg': 'fail' if s else 'success', 'data': m}


@api.route('/subnets', methods=['POST'])
def create_subnet():
    x_user = request.headers['user_name']

    args = request.form
    subnet_name = args['name']
    subnet_cidr = args['cidr']
    network_id = args['network_id']
    rtb_id = args['rtb_id']
    az = args.get('az', '')

    cluster_id = 0

    s, m = utils.create_subnet(cluster_id, subnet_name,
                               subnet_cidr, network_id)
    if s:
        return {'status': 1, 'msg': 'fail', 'data': m}

    subnet = m
    utils.record_subnet(network_id=network_id, subnet_id=subnet['id'],
                        name=subnet_name, cidr=subnet_cidr,
                        status='ACTIVE', creator=x_user,
                        create_time=utils.curtime())
    # record route
    utils.record_route(rtb_id=rtb_id,
                       subnet_id=subnet['id'],
                       type='Local',
                       az=az,
                       is_local=1,
                       creator=x_user,
                       create_time=utils.curtime())

    return {'status': 0, 'msg': 'success', 'data': subnet}


# Subnet
@api.route('/subnets/<subnet_id>')
def show_subnet(subnet_id):
    s, m = utils.show_subnet(0, subnet_id)
    return {'status': s, 'msg': 'fail' if s else 'success', 'data': m}


@api.route('/subnets/<subnet_id>', methods=['DELETE'])
def delete_subnet(subnet_id):
    cluster_id = 0
    s, m = utils.delete_subnet(subnet_id, cluster_id)
    return {
        'status': s,
        'msg': 'fail' if s else 'success',
        'data': m,
    }


# Routers
@api.route('/routers')
def list_routers():
    args = request.args

    project_id = args['project_id']
    cluster_id = 0
    s, m = utils.list_routers(project_id, cluster_id)
    return {'status': s, 'msg': 'fail' if s else 'success', 'data': m}


@api.route('/routers', methods=['POST'])
def create_router():
    args = request.form

    # project_id = args['project_id']
    router_name = args['name']

    cluster_id = 0
    s, m = utils.create_router(cluster_id, router_name)
    return {
        'status': s,
        'msg': 'fail' if s else 'success',
        'data': m,
    }


@api.route('/routers/<router_id>')
def show_route(router_id):
    s, m = utils.show_router(0, router_id)
    return {'status': s, 'msg': 'fail' if s else 'success', 'data': m}


@api.route('/routers/<router_id>', methods=['DELETE'])
def delete_route(router_id):
    resp = {
        'status': 0,
        'msg': 'success',
        'data': 'Delete %s successfully' % router_id,
    }
    return resp


@api.route('/routers/<router_id>/interfaces', methods=['POST'])
def add_router_interface(router_id):
    """ 给某一个路由器添加接口.

    这真是狗血的设计,没法玩了.
    项目 -> 多集群 -> 还要维护不同集群的router(ID还不一样), 但是让用户感觉是一个.
    对老版本的集群兼容性就更别提了.
    """
    args = request.form
    subnet_id = args['subnet_id']

    s, m = utils.get_project_by_router(router_id)
    if s:
        return {'status': 1, 'msg': 'abort', 'data': m}

    project = m
    # project_id = project['project_id']
    cluster_id = project['cluster_id']

    s, m = utils.add_router_interface(cluster_id, router_id, subnet_id)
    return {
        'status': s,
        'msg': 'fail' if s else 'success',
        'data': m,
    }


@api.route('/routers/<router_id>/interface', methods=['DELETE'])
def remove_router_interface(router_id):
    args = request.form
    subnet_id = args['subnet_id']

    s, m = utils.get_project_by_router(router_id)
    if s:
        return {'status': 1, 'msg': 'abort', 'data': m}

    # FIXME
    project = m
    # project_id = project['project_id']
    cluster_id = project['cluster_id']

    s, m = utils.remove_router_interface(cluster_id, router_id, subnet_id)
    return {
        'status': s,
        'msg': 'fail' if s else 'success',
        'data': m,
    }


@api.route('/routes')
def list_routes():
    args = request.args
    project_id = args['project_id']
    s, m = utils.list_routes(project_id)
    if s or not m:
        return {'status': s, 'msg': 'fail', 'data': m}

    routes = m
    for route in routes:
        error, result = utils.list_subnets_by_rtb_id(route['rtb_id'])
        LOGGER.debug('list subnets: %s, %s', error, result)
        if not error:
            route['subnet_count'] = len(result)
        else:
            route['subnet_count'] = []

    return {'status': s, 'msg': 'success', 'data': routes}


# @api.route('/routes/remove', methods=['DELETE'])
# def remove_routes():
#     args = request.form

#     project_id = args['project_id']
#     router_id = args['router_id']
#     subnet_id = args['subnet_id']
#     cluster_id = 0

#     s, m = utils.remove_router_interface(cluster_id, router_id, subnet_id)
#     return {
#         'status': s,
#         'msg': 'fail' if s else 'success',
#         'data': m,
#     }
